﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.UI;
using System.IO;
using MvcContrib;
using System.Web.Routing;
using System.Globalization;
using System.Web;
using System.Linq.Expressions;
using System.Text.RegularExpressions;

namespace MvcShop.Extensions.Html
{
    public static class HtmlExtensions
    {
        public static string If(this HtmlHelper helper,bool condition,Func<string> value,Func<string> elseValue)
        {
            return condition ? value() : elseValue();
        }

        public static string If(this HtmlHelper helper, bool condition, Func<string> value)
        {
            return condition ? value() : "";
        }

        public static void If(this HtmlHelper helper, bool condition, Action action, Action elseAction)
        { 
            if(condition)
            {
               action();
            }
            else if(elseAction !=null)
            {
                elseAction();
            }
        }

        public static void ForEach(this HtmlHelper helper,int includeMin,int excludeMax,Action<int> action)
        {
            for (int i = includeMin; i < excludeMax; i++) action(i);
        }

        public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
        {
            foreach (var item in items) action(item);
        }

        public static void ForEach<T>(this IEnumerable<T> items, Action<T,int> action)
        {
            int index = 0;
            foreach (var item in items) action(item, index++);
        }

        public static string Tick(this HtmlHelper htmlHelper, bool ticked)
        {
            HtmlTextWriter writer = new HtmlTextWriter(new StringWriter());

            if (ticked)
            {
                writer.AddAttribute("class", "tick");
            }
            else
            {
                writer.AddAttribute("class", "cross");
            }
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.Write("&nbsp;&nbsp;&nbsp;&nbsp;");
            writer.RenderEndTag();
            return writer.InnerWriter.ToString();
        }

        #region ==== SearchLink ====
        public static string ProductShow(this HtmlHelper html, string linkName, string showType)
        {
            string _path = html.ViewContext.HttpContext.Request.Path;
            string queryString = html.ViewContext.HttpContext.Request.QueryString.ToString();
            if (queryString.IndexOf("Show=") < 0)
            {
                queryString += "&Show=" + showType;
            }

            Regex re = new Regex(@"Show=\w+", RegexOptions.IgnoreCase);
            string result = re.Replace(queryString, "Show={0}");

            return "<a href=\"{0}\">{1}</a>".With(_path + "?" + string.Format(result, showType), linkName);
        }
        #endregion

        #region ==== Form ====
        public static IDisposable MultipartForm(this HtmlHelper helper)
        {
            string action = helper.ViewContext.RouteData.GetRequiredString("action");
            string controller = helper.ViewContext.RouteData.GetRequiredString("controller");
            return helper.BeginForm(action, controller, FormMethod.Post, new Hash(enctype => "multipart/form-data"));
        }

        public static IDisposable MultipartForm(this HtmlHelper helper,object html)
        {
            string action = helper.ViewContext.RouteData.GetRequiredString("action");
            string controller = helper.ViewContext.RouteData.GetRequiredString("controller");
            return helper.BeginForm(action, controller, FormMethod.Post, html);
        }
        #endregion

        #region ==== meta ====
        public static string Keywords(this HtmlHelper helper, string keyWords)
        {
            return "<meta name=\"keywords\" content=\"{0}\">".With(keyWords);
        }

        public static string Description(this HtmlHelper helper, string description)
        {
            return "<meta name=\"Description\" content=\"{0}\">".With(description);
        }
        #endregion

        #region ==== RenderActionExtensions ====
        public static void RenderAction<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string area) where TController : Controller  
        {  
            RouteValueDictionary rvd = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);  
  
            rvd["area"] = area;  
  
            foreach (var entry in helper.ViewContext.RouteData.Values)  
            {  
               if (!rvd.ContainsKey(entry.Key))  
               {  
                   rvd.Add(entry.Key, entry.Value);  
               }  
            }  
 
           helper.RenderRoute(rvd);  
        }

        public static void RenderSubAction<TController>(this HtmlHelper helper, Expression<Action<TController>> action) where TController : Controller
        {
            RouteValueDictionary routeValuesFromExpression = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action);
            helper.RenderRoute(routeValuesFromExpression);
        } 

        public static void RenderSubAction(this HtmlHelper helper, string actionName)
        {
            helper.RenderSubAction(actionName, null);
        }

        public static void RenderSubAction(this HtmlHelper helper, string actionName, string controllerName)
        {
            helper.RenderSubAction(actionName, controllerName, null);
        }

        public static void RenderSubAction(this HtmlHelper helper, string actionName, string controllerName, object routeValues)
        {
            helper.RenderSubAction(actionName, controllerName, new RouteValueDictionary(routeValues));
        }

        public static void RenderSubAction(this HtmlHelper helper, string actionName, string controllerName, RouteValueDictionary routeValues)
        {
            RouteValueDictionary dictionary = routeValues != null ? new RouteValueDictionary(routeValues)
                : new RouteValueDictionary();
            foreach (var pair in helper.ViewContext.RouteData.Values)
            {
                if (!dictionary.ContainsKey(pair.Key))
                {
                    dictionary.Add(pair.Key, pair.Value);
                }
            }
            if (!string.IsNullOrEmpty(actionName))
            {
                dictionary["action"] = actionName;
            }
            if (!string.IsNullOrEmpty(controllerName))
            {
                dictionary["controller"] = controllerName;
            }
            helper.RenderRoute(dictionary);
        }

        public static void RenderRoute(this HtmlHelper helper, RouteValueDictionary routeValues)
        {
            var routeData = new RouteData();
            foreach (var pair in routeValues)
            {
                routeData.Values.Add(pair.Key, pair.Value);
            }
            HttpContextBase httpContext = new OverrideRequestHttpContextWrapper(HttpContext.Current);
            var context = new RequestContext(httpContext, routeData);
            bool validateRequest = helper.ViewContext.Controller.ValidateRequest;
            new RenderSubActionMvcHandler(context, validateRequest).ProcessRequestInternal(httpContext);
        }
        #endregion

        #region Nested type: RenderSubActionMvcHandler

        private class RenderSubActionMvcHandler : MvcHandler
        {
            private bool _validateRequest;
            public RenderSubActionMvcHandler(RequestContext context, bool validateRequest)
                : base(context)
            {
                _validateRequest = validateRequest;
            }

            protected override void AddVersionHeader(HttpContextBase httpContext) { }

            public void ProcessRequestInternal(HttpContextBase httpContext)
            {
                AddVersionHeader(httpContext);
                string requiredString = RequestContext.RouteData.GetRequiredString("controller");
                IControllerFactory controllerFactory = ControllerBuilder.Current.GetControllerFactory();
                IController controller = controllerFactory.CreateController(RequestContext, requiredString);
                if (controller == null)
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,
                        "The IControllerFactory '{0}' did not return a controller for a controller named '{1}'.",
                        new object[] { controllerFactory.GetType(), requiredString }));
                }
                try
                {
                    ((ControllerBase)controller).ValidateRequest = _validateRequest;
                    controller.Execute(RequestContext);
                }
                finally
                {
                    controllerFactory.ReleaseController(controller);
                }
            }
        }

        private class OverrideHttpMethodHttpRequestWrapper : HttpRequestWrapper
        {
            public OverrideHttpMethodHttpRequestWrapper(HttpRequest httpRequest) : base(httpRequest) { }

            public override string HttpMethod
            {
                get { return "GET"; }
            }
        }

        private class OverrideRequestHttpContextWrapper : HttpContextWrapper
        {
            private readonly HttpContext _httpContext;
            public OverrideRequestHttpContextWrapper(HttpContext httpContext)
                : base(httpContext)
            {
                _httpContext = httpContext;
            }

            public override HttpRequestBase Request
            {
                get { return new OverrideHttpMethodHttpRequestWrapper(_httpContext.Request); }
            }
        }

        #endregion

    }
}
